package com.sky.aspect;


import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.entity.Employee;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Component
@Aspect
@Slf4j
public class AutoFillAspect {
    // 表达式
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill))")
    public void pc() {
    }

    ;

    @Before("pc()")
    public void AutoFill(JoinPoint joinPoint) throws Exception {
        log.info("公共字段填充....");

        // 1.获取被拦截的方法上的数据库操作类型 因为UPDATE和INSERT要修改的字段不同
        MethodSignature signature = (MethodSignature) joinPoint.getSignature(); // 获得方法签名对象 格式：方法(参数类型)  insert(Employee)
        AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class); // 获取方法签名上的注解对象
        OperationType operationType = autoFill.value(); // 获取注解值，即枚举里面用来标记数据库操作类型的UPDATE和INSERT

        // 2.获取被拦截方法的实体对象，规定实体对象默认放在第一个参数
        Object[] args = joinPoint.getArgs(); // 获取所有参数
        if (args == null || args.length == 0) return; // 异常判断
        Object o = args[0]; // 获取第一个参数，即实体对象

        // 3.准备赋值的数据
        LocalDateTime now = LocalDateTime.now();
        Long currentId = BaseContext.getCurrentId();

        // 4.获取类对象的字节码对象
        Class<?> oClass = o.getClass();

        // 5.根据不同的操作类型为属性赋值：通过反射
        if (operationType == OperationType.INSERT) {
            Method setCreateTimeMehtod = oClass.getMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
            Method setUpdateTimeMethod = oClass.getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
            Method setCreateUserMethod = oClass.getMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
            Method setUpdateUserMethod = oClass.getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

            setCreateTimeMehtod.invoke(o, now);
            setUpdateTimeMethod.invoke(o, now);
            setCreateUserMethod.invoke(o, currentId);
            setUpdateUserMethod.invoke(o, currentId);
        }

        if (operationType == OperationType.UPDATE){
            Method setUpdateTimeMethod = oClass.getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
            Method setUpdateUserMethod = oClass.getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

            setUpdateTimeMethod.invoke(o, now);
            setUpdateUserMethod.invoke(o, currentId);
        }


    }
}
